/****************************************************
File Name:head.c
Author: Abby Cin
Mail: abbytsing@gmail.com
Created Time: Tue 12 Aug 2014 04:53:41 PM CST
*****************************************************/
// commandline format Tue Aug 12 18:02:27 2014 commandline
#define _POSIX_C_SOURCE 199309
#include "head.h"
#include <string.h>
#include <time.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <signal.h>
#include <errno.h>
#include<stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
void
eRR (char *func)
{
  perror (func);
  exit (errno);
}

unsigned long
trans (const char *str1, const char *str2, char option)
{
  unsigned long number, suber, subee;
  if (option == 'f')
    {
      suber =
	atol (&str1[11]) * 3600 + atol (&str1[14]) * 60 + atol (&str1[17]);
      subee =
	atol (&str2[11]) * 3600 + atol (&str2[14]) * 60 + atol (&str2[17]);
    }
  else if (option == 'c')
    {
      suber = atol (&str1[0]) * 3600 + atol (&str1[3]) * 60 + atol (&str1[6]);
      subee =
	atol (&str2[11]) * 3600 + atol (&str2[14]) * 60 + atol (&str2[17]);
    }
  if (subee > suber)
    number = suber + 24 * 3600 - subee;
  else
    number = suber - subee;
  return number;
}

char *
getlocaltime (void)
{
  time_t t;
  char *loctime;
  t = time (NULL);
  loctime = ctime (&t);
  return loctime;
}

job
getfromfile (const char *path)
{
  int fd, i = 25, j = 0;
  job res;			// be used to return the split time and commandline
  struct stat buf;
  off_t size;
  char *cmdline;
  char *loctime;
  loctime = getlocaltime ();
  stat (path, &buf);
  size = buf.st_size;
  cmdline = malloc (size);
//res.command=malloc(size);
// when comment this, this program works!! but why?? commandline length shall NOT be too long
  if ((fd = open (path, O_RDWR)) == -1)
    eRR ("open commandline file");
  if (read (fd, cmdline, size - 1) == -1)	// when size -1 , this program works!!! but why???
    eRR ("read commandline file");

  while (cmdline[i] != '\0')
    {
      res.command[j] = cmdline[i];
      i++;j++;
    }

  close (fd);

  res.relative_time = trans (cmdline, loctime, 'f');
  free (cmdline);
  return res;
}

job
getfromcmd (const char *cmd1, char *cmd2)
{
  job res;
  char *loctime;
//loctime = malloc (100);
  loctime = getlocaltime ();
// timer time format 19:00:00
  res.relative_time = trans (cmd1, loctime, 'c');
  res.command = cmd2;
//free (loctime);
  return res;
}

job
gettime_cmd (const char *option, const char *trtime, char *cmd)
{
  job timercmd;
  if (strcmp (option, "-f") == 0)
    {
// get timer time from filepath 'res'
// -f filepath
      if (trtime == NULL)
	{
	  printf ("with a filepath which contains the timer info\n");
	  exit (EXIT_FAILURE);
	}
      timercmd = getfromfile (trtime);
    }
  else if (strcmp (option, "-c") == 0)
    {
// get timer time from commandline
// -c time commandline
      if (trtime == NULL || cmd == NULL)
	{
	  printf ("run with two argument; example: -c 19:00:00 \"ls\"\n");
	  exit (EXIT_SUCCESS);
	}
      timercmd = getfromcmd (trtime, cmd);
    }
  else
    {
// error handle
      printf ("the first parameter must be \"-f\" or \"-c\"\n\
if you wanna set a timer\n");
      exit (EXIT_FAILURE);
    }
  return timercmd;
}

void
showtimer (job arg, char option)
{
  FILE *fp;
  char *buf;
  long size;
  if (option == 'w')
    {
      fp = fopen ("info", "a+");
      fprintf (fp, "%ld\t%s%s %s %s %lu %s %s %c", (long) arg.pid + 1,
	       "START: ", __DATE__, __TIME__, "EXPIRATION: ",
	       arg.relative_time, "CMD: ", arg.command, '\n');
    }
  else if (option == 'r')
    {
      if (access ("info", F_OK) != 0)
	{
	  printf ("\"info\" not found, can't showtimer\n");
	  exit (EXIT_FAILURE);
	}
      else
	{
	  fp = fopen ("info", "r");
	  fseek (fp, 0, SEEK_END);
	  size = ftell (fp);
	  fseek (fp, 0, SEEK_SET);
	  buf = malloc (size);
	  fread (buf, (size_t) size, 1, fp);
	  printf ("%s\n", buf);
	  free (buf);
	}
    }
  fclose (fp);
}

void
exec (union sigval val)
{
  system (val.sival_ptr);	// exec the command
  raise (15);
}

void
settimer (job arg)
{
  showtimer (arg, 'w');
  struct sigevent sevp;
  timer_t timerid;
  struct itimerspec value;
  sevp.sigev_notify = SIGEV_THREAD;
  sevp.sigev_notify_function = exec;
  sevp.sigev_notify_attributes = NULL;
  sevp.sigev_value.sival_ptr = (void *) arg.command;
/* sival_ptr in prototype union sigval */
  value.it_interval.tv_sec = 0;
  value.it_interval.tv_nsec = 0;
  value.it_value.tv_sec = arg.relative_time;
  value.it_value.tv_nsec = 0;
  if (timer_create (CLOCK_REALTIME, &sevp, &timerid) == -1)
    eRR ("timer_create");
  if (timer_settime (timerid, 0, &value, NULL) == -1)
    eRR ("timer_settime");
}

void
deltimer (char *arg)
{
  if (access ("info", F_OK) != 0)
    {
      printf ("\"info\" not found, can't operat delete action\n");
      exit (EXIT_FAILURE);
    }
  struct stat filestat;
  stat ("info", &filestat);
  if (filestat.st_size < 4)
    {
      remove ("info");
      fprintf (stderr, "%s\n", "All timers have been deleted");
      exit (EXIT_FAILURE);
    }
  int fd;
  char rdpid[filestat.st_size];	// store entire file
  char stpid[6];		// assert longest pid length
  if ((fd = open ("info", O_RDWR)) == -1)
    eRR ("open");
  if (read (fd, rdpid, filestat.st_size) == -1)
    eRR ("read");
  close (fd);
  if (strcmp (arg, "-d") == 0)
    {
      int len, i = 0, size;
      char *space;		// space for re-write temp store
      for (len = 0; rdpid[len] != '\n'; ++len);
      size = filestat.st_size - len;
      space = malloc (size);
      len = len + 1;		// use to remove another '\n'
      while (rdpid[len] != '\0')
	{
	  space[i] = rdpid[len];
	  len++;
	  i++;
	}
      for (i = 0; rdpid[i] != '\t'; i++)
	stpid[i] = rdpid[i];
      kill (atoi (stpid), 15);
      remove ("info");
      if ((fd = open ("info", O_RDWR | O_CREAT, 00644)) == -1)
	eRR ("open");
      if (write (fd, space, size) == -1)
	eRR ("write");
      close (fd);
    }
  else if (strcmp (arg, "-a") == 0)
    {
      char pidtab[1000][6];	// info file can contain no more than 1000 lines
      int i, j, k, fd;
      char space[filestat.st_size];
      if ((fd = open ("info", O_RDWR)) == -1)
	eRR ("open");
      if (read (fd, space, filestat.st_size) == -1)
	eRR ("read");
      close (fd);
      i = j = k = 0;
      while (space[i] != '\0')
	{
	  if (space[i] == '\n')
	    {
	      j++;
	      k = 0;
	    }
	  pidtab[j][k] = space[i];
	  k++;
	  i++;
	}
      i = j;
      for (j = 0; j < i; j++)
	kill (atoi (pidtab[j]), 15);
      remove ("info");
      printf ("All timer deleted\n");
      exit (EXIT_SUCCESS);
    }
  else
    {
      printf ("unknown option, use \"--help\" to get how to use\n");
      exit (EXIT_FAILURE);
    }
}
